#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stropts.h>
#include <errno.h>
#include <linux/fs.h>

#define FNAME "/sys/firmware/efi/efivars/SystemAudioVolume-7c436110-ab2a-4bbb-a880-fe41995c9f82"

static int efivarfs_fd_immutable(int fd, bool immutable)
{
    unsigned int flags;
    int rc = 0;

    rc = ioctl(fd, FS_IOC_GETFLAGS, &flags);
    if (rc < 0) {
        return -1;
    }

    if ((immutable && !(flags & FS_IMMUTABLE_FL)) ||
        (!immutable && (flags & FS_IMMUTABLE_FL))) {
        if (immutable) {
            flags |= FS_IMMUTABLE_FL;
        }
        else {
            flags &= ~FS_IMMUTABLE_FL;
        }

        rc = ioctl(fd, FS_IOC_SETFLAGS, &flags);
        if (rc < 0) {
            return -1;
        }
    }

    return 0;
}

static int efivarfs_fname_immutable(char *fname, bool immutable)
{
    int fd = open(fname, O_RDONLY);
    if (fd < 0) {
        return -1;
    }

    if (efivarfs_fd_immutable(fd, immutable) < 0) {
        close(fd);
        return -1;
    }

    close(fd);

    return 0;
}

static void __usage(int argc, char **argv)
{
    printf("usage: %s [0-100]\n", argv[0]);
}

static void __get()
{
    int fd = open(FNAME, O_RDONLY);
    if (fd == -1) {
        perror("open");
        exit(-1);
    }

    unsigned char x[5];
    if (5 != read(fd, x, 5)) {
        perror("read");
        exit(-1);
    }
    close(fd);

    printf("%u\n", x[4]);
}

static void __set(unsigned char vol)
{
    int fd = open(FNAME, O_WRONLY|O_CREAT|O_EXCL, 0644);
    if (fd == -1) {
        efivarfs_fname_immutable(FNAME, false);
        unlink(FNAME);
        fd = open(FNAME, O_WRONLY|O_CREAT|O_EXCL, 0644);
    }
    if (fd == -1) {
        perror("open");
        exit(-1);
    }

    unsigned char x[5] = {0x07, 0x00, 0x00, 0x00, vol};
    if (efivarfs_fd_immutable(fd, false) < 0) {
        perror("efivarfs_fd_immutable");
        exit(-1);
    }
    if (5 != write(fd, x, 5)) {
        perror("write");
        exit(-1);
    }
    efivarfs_fd_immutable(fd, true);

    close(fd);
}

int main(int argc, char **argv)
{
    if (geteuid() != 0) {
        printf("MUST BE 'ROOT' privilege\n");
        return -1;
    }

    if (argc == 2) {
        int vol = atoi(argv[1]);
        if (vol < 0 || vol > 100) {
            __usage(argc, argv);
            return -1;
        }
        __set(vol);
    }
    __get();

    return 0;
}
